package com.powernode.shop.aspect;

import com.alibaba.fastjson.JSON;
import com.powernode.shop.anno.Log;
import com.powernode.shop.domain.SysLog;
import com.powernode.shop.domain.SysUser;
import com.powernode.shop.mapper.SysUserMapper;
import com.powernode.shop.service.SysLogService;
import com.powernode.shop.thread.ManagerThreadPool;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.lang.reflect.Method;
import java.util.Date;

/**
 * @author ZHAOZHENYU
 * @since 2022/10/11
 */

@Component
@Aspect
public class LogAspect {

    @Autowired(required = false)
    private SysUserMapper sysUserMapper;

    @Autowired
    private SysLogService sysLogService;

    /**
     *  自定义日志注解使用再Controller方法上,只要作用了，就自动往sys_log表中添加一行记录
     *  这里要使用切面，切入点就是controller方法，那么把sys_log表中所有列需要的信息都需要在这里
     *  补充完成，直接写入表中去
     *
     *  sys_log表中的字段名称：
     *          username    当前操作用户名
     *          operation   日志记录描述信息
     *          method      调用方法全名称   包名+方法名
     *          params      方法参数
     *          time        方法执行时间
     *          ip          调用接口的ip地址
     *          create_date  该日志创建时间
     *
     *
     * @param joinPoint
     * @return
     */
    @Around(value = "@annotation(com.powernode.shop.anno.Log)")
    public Object logAround(ProceedingJoinPoint joinPoint){
        // 切入点传入的参数
        Object[] args = joinPoint.getArgs();
        // 获取签名方法
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        // 获取方法对象
        Method method = signature.getMethod();
        // 获取方法注解
        Log logAnno = method.getAnnotation(Log.class);
        // 获取属性值
        String operation = logAnno.operation();
        // 获取方法全名
        String methodAllName = method.getDeclaringClass().getName();
        //获取ip
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        String ip = requestAttributes.getRequest().getRemoteHost();
        // 获取方法执行的时间 开始-结束
        long startTime = System.currentTimeMillis();
        Object result = null;
        try {
            // 执行结果返回出去 不影响源代码
            result = joinPoint.proceed(args);
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        long endTime = System.currentTimeMillis();
        Long execTime = endTime - startTime;
        // 获取用户id
        String userId = SecurityContextHolder.getContext().getAuthentication().getPrincipal().toString();
        // 得到用户对象数据
        SysUser sysUser = sysUserMapper.selectById(userId);
        // 放入数据库
        SysLog sysLog = SysLog.builder()
                .ip(ip)
                .createDate(new Date())
                .method(methodAllName)
                .operation(operation)
                .params(JSON.toJSONString(sysUser))
                .time(endTime)
                .username(sysUser.getUsername())
                .build();
        // 添加线程池 异步提交
        ManagerThreadPool.threadPoolExecutor.execute(()->{
            sysLogService.save(sysLog);
        });
        // 返回执行结果 只做增强
        return result;
    }


}
